//
//  OssService.m
//  OssIOSDemo
//
//  Created by jingdan on 17/11/23.
//  Copyright © 2015年 Ali. All rights reserved.
//

#import <AliyunOSSiOS/OSSService.h>
#import "OssService.h"

@interface OssService ()
/** ossTask */
@property(nonatomic,strong) OSSTask *task;
@end

@implementation OssService
{
    OSSClient * client;
    NSString * endPoint;
    NSString * callbackAddress;
    NSMutableDictionary * uploadStatusRecorder;
    NSString * currentUploadRecordKey;
    OSSPutObjectRequest * putRequest;
    OSSGetObjectRequest * getRequest;
    
    // 简单起见，全局只维护一个断点上传任务
    OSSResumableUploadRequest * resumableRequest;
    BOOL isCancelled;
    BOOL isResumeUpload;
}

- (id)initWithEndPoint:(NSString *)enpoint {
    if (self = [super init]) {
        endPoint = enpoint;
        isResumeUpload = NO;
        isCancelled = NO;
        currentUploadRecordKey = @"";
        uploadStatusRecorder = [NSMutableDictionary new];
        [self ossInit];
    }
    return self;
}

/**
 *    @brief    初始化获取OSSClient
 */
- (void)ossInit {
//     移动终端是一个不受信任的环境，使用主账号AK，SK直接保存在终端用来加签请求，存在极高的风险。建议只在测试时使用明文设置模式，业务应用推荐使用STS鉴权模式。
//     STS鉴权模式可通过https://help.aliyun.com/document_detail/31920.html文档了解更多
//     主账号方式
//     id<OSSCredentialProvider> credential = [[OSSPlainTextAKSKPairCredentialProvider alloc] initWithAccessKeyId:@"Aliyun_AK" secretKeyId:@"Aliyun_SK"];
//     如果用STS鉴权模式，推荐使用OSSAuthCredentialProvider方式直接访问鉴权应用服务器，token过期后可以自动更新。
//     详见：https://help.aliyun.com/document_detail/31920.html
//     OSSClient的生命周期和应用程序的生命周期保持一致即可。在应用程序启动时创建一个ossClient，在应用程序结束时销毁即可。
//    id<OSSCredentialProvider> credential = [[OSSAuthCredentialProvider alloc] initWithAuthServerUrl:STS_AUTH_URL];
//    [[OSSAuthCredentialProvider alloc] initWithAuthServerUrl:@""];
    
//    client = [[OSSClient alloc] initWithEndpoint:endPoint credentialProvider:credential];
    
    
    id<OSSCredentialProvider> credential = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * {
        OSSTaskCompletionSource * tcs = [OSSTaskCompletionSource taskCompletionSource];
        
        [MBManager showLoading];
        NSDictionary *body = @{};
        NSError *error;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error];
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        NSMutableURLRequest *req = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:OSS_STSAliR parameters:nil error:nil];
        [req setValue:@"application/text" forHTTPHeaderField:@"Content-Type"];
        [req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [req setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
        [[manager dataTaskWithRequest:req completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            [MBManager hideAlert];
            if (!error) {
                DLog(@"Reply JSON: %@", responseObject);
                NSInteger msgcode = [responseObject[@"msgcode"] integerValue];
                NSDictionary *value = @{@"AccessKeyId" : responseObject[@"value"][@"accesskeyid"],
                                        @"AccessKeySecret" : responseObject[@"value"][@"accesskeysecret"],
                                        @"SecurityToken" : responseObject[@"value"][@"securitytoken"],
                                        @"Expiration" : responseObject[@"value"][@"expiration"]
                                        };
                NSString *message = responseObject[@"message"];
                if (msgcode == 1) {
                    
                    [tcs setResult:value];
                } else {
                    [MBManager showBriefAlert:message];
                }
            } else {
                [tcs setError:error];
                DLog(@"Error: %@, %@, %@", error, response, responseObject);
                [MBManager showBriefAlert:@"网络错误"];
                return;
            }
        }] resume];
        
        
        // 需要阻塞等待请求返回
        [tcs.task waitUntilFinished];
        // 解析结果
        if (tcs.task.error) {
            DLog(@"get token error: %@", tcs.task.error);
            return nil;
        } else {
            // 返回数据是json格式，需要解析得到token的各个字段
            NSDictionary * object = [tcs.task.result mutableCopy];
            OSSFederationToken * token = [OSSFederationToken new];
            token.tAccessKey = [object objectForKey:@"AccessKeyId"];
            token.tSecretKey = [object objectForKey:@"AccessKeySecret"];
            token.tToken = [object objectForKey:@"SecurityToken"];
            token.expirationTimeInGMTFormat = [object objectForKey:@"Expiration"];
            DLog(@"get token: %@", token);
            return token;
        }
    }];
    client = [[OSSClient alloc] initWithEndpoint:endPoint credentialProvider:credential];
}


/**
 *    @brief    设置server callback地址
 */
- (void)setCallbackAddress:(NSString *)address {
    callbackAddress = address;
}

/**
 *    @brief    上传图片
 *
 *    @param     objectKey     objectKey
 *    @param     filePath     路径
 */
- (void)asyncPutImage:(NSString *)objectKey
        localFilePath:(NSString *)filePath {
    
    if (objectKey == nil || [objectKey length] == 0) {
        return;
    }
    
    putRequest = [OSSPutObjectRequest new];
    putRequest.bucketName = OSS_BUCKET_NAME;
    putRequest.objectKey = objectKey;
    putRequest.uploadingFileURL = [NSURL fileURLWithPath:filePath];
    putRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
        DLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    };
    if (callbackAddress != nil) {
        putRequest.callbackParam = @{
                                     @"callbackUrl": callbackAddress,
                                     // callbackBody可自定义传入的信息
                                     @"callbackBody": @"filename=${object}"
                                     };
    }
    OSSTask * task = [client putObject:putRequest];
    [task continueWithBlock:^id(OSSTask *task) {
        OSSPutObjectResult * result = task.result;
        // 查看server callback是否成功
        if (!task.error) {
            NSLog(@"Put image success!");
            NSLog(@"server callback : %@", result.serverReturnJsonString);
            dispatch_async(dispatch_get_main_queue(), ^{
                DLog(@"普通上传 === Success!");
            });
        } else {
            DLog(@"Put image failed, %@", task.error);
            if (task.error.code == OSSClientErrorCodeTaskCancelled) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 ==== 任务取消!");
                });
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 === Failed!");
                });
            }
        }
        putRequest = nil;
        return nil;
    }];
}

/**
 *    @brief    上传图片
 *
 *    @param     objectKey     objectKey
 *    @param     uploadData    数据
 */
- (void)asyncPutImage:(NSString *)objectKey
                 data:(NSData *)uploadData success:(void(^)(NSString *imgUrl))success failure:(void(^)(NSString * errmsg, NSString *objectKey, NSData *uploadData))failure {
    
    if (objectKey == nil || [objectKey length] == 0) {
        return;
    }
    
    putRequest = [OSSPutObjectRequest new];
    putRequest.bucketName = OSS_BUCKET_NAME;
    putRequest.objectKey = objectKey;
    putRequest.uploadingData = uploadData;
    putRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
        DLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    };
    if (callbackAddress != nil) {
        putRequest.callbackParam = @{
                                     @"callbackUrl": callbackAddress,
                                     // callbackBody可自定义传入的信息
                                     @"callbackBody": @"filename=${object}"
                                     };
    }
    OSSTask * task = [client putObject:putRequest];
    [task continueWithBlock:^id(OSSTask *task) {
        OSSPutObjectResult * result = task.result;
        // 查看server callback是否成功
        if (!task.error) {
            NSLog(@"Put image success!");
            NSLog(@"server callback : %@", result.serverReturnJsonString);
            dispatch_async(dispatch_get_main_queue(), ^{
                DLog(@"普通上传 === Success!");
                if (success) {
                    success([NSString stringWithFormat:@"%@%@",IMG_OSS,objectKey]);
                }
            });
        } else {
            DLog(@"Put image failed, %@", task.error);
            if (task.error.code == OSSClientErrorCodeTaskCancelled) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 ==== 任务取消!");
                    if (failure) {
                        failure(@"任务取消!",objectKey,uploadData);
                    }
                });
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 === Failed!");
                    if (failure) {
                        failure(@"上传失败!",objectKey,uploadData);
                    }
                });
            }
        }
        putRequest = nil;
        return nil;
    }];
}
/**
 *    @brief    上传图片
 *
 *    @param     objectKey     objectKey
 *    @param     uploadData    数据
 */
- (void)asyncPutImage:(NSString *)objectKey
                 data:(NSData *)uploadData {
    
    if (objectKey == nil || [objectKey length] == 0) {
        return;
    }
    
    putRequest = [OSSPutObjectRequest new];
    putRequest.bucketName = OSS_BUCKET_NAME;
    putRequest.objectKey = objectKey;
    putRequest.uploadingData = uploadData;
    putRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
        DLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    };
    if (callbackAddress != nil) {
        putRequest.callbackParam = @{
                                     @"callbackUrl": callbackAddress,
                                     // callbackBody可自定义传入的信息
                                     @"callbackBody": @"filename=${object}"
                                     };
    }
    OSSTask * task = [client putObject:putRequest];
    [task continueWithBlock:^id(OSSTask *task) {
        OSSPutObjectResult * result = task.result;
        // 查看server callback是否成功
        if (!task.error) {
            NSLog(@"Put image success!");
            NSLog(@"server callback : %@", result.serverReturnJsonString);
            dispatch_async(dispatch_get_main_queue(), ^{
                DLog(@"普通上传 === Success!");
            });
        } else {
            DLog(@"Put image failed, %@", task.error);
            if (task.error.code == OSSClientErrorCodeTaskCancelled) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 ==== 任务取消!");
                });
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通上传 === Failed!");
                });
            }
        }
        putRequest = nil;
        return nil;
    }];
}

/**
 *    @brief    下载图片
 */
- (void)asyncGetImage:(NSString *)objectKey {
    if (objectKey == nil || [objectKey length] == 0) {
        return;
    }
    getRequest = [OSSGetObjectRequest new];
    getRequest.bucketName = OSS_BUCKET_NAME;
    getRequest.objectKey = objectKey;
    OSSTask * task = [client getObject:getRequest];
    [task continueWithBlock:^id(OSSTask *task) {
//        OSSGetObjectResult * result = task.result;
        if (!task.error) {
            NSLog(@"Get image success!");
            dispatch_async(dispatch_get_main_queue(), ^{
                DLog(@"普通下载 === Success!");
            });
        } else {
            DLog(@"Get image failed, %@", task.error);
            if (task.error.code == OSSClientErrorCodeTaskCancelled) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通下载 ==== 任务取消!");
                });
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    DLog(@"普通下载 ===== Failed!");
                });
            }
        }
        getRequest = nil;
        return nil;
    }];
}

/**
 *    @brief    普通上传/下载取消
 */
- (void)normalRequestCancel {
    if (putRequest) {
        [putRequest cancel];
    }
    if (getRequest) {
        [getRequest cancel];
    }
}

@end

